/**
 * Copyright 2019 吉鼎科技.

 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package cn.easyplatform.web.controller.admin;

import cn.easyplatform.lang.Files;
import cn.easyplatform.lang.Strings;
import cn.easyplatform.web.WebApps;
import cn.easyplatform.web.contexts.Contexts;
import cn.easyplatform.web.dialog.MessageBox;
import cn.easyplatform.web.ext.cmez.CMeditor;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.FastDateFormat;
import org.zkoss.util.resource.Labels;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.event.*;
import org.zkoss.zk.ui.select.SelectorComposer;
import org.zkoss.zk.ui.select.annotation.Listen;
import org.zkoss.zk.ui.select.annotation.Wire;
import org.zkoss.zkmax.zul.Filedownload;
import org.zkoss.zul.*;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FilenameFilter;
import java.io.IOException;
import java.util.Arrays;
import java.util.Stack;

/**
 * @Author: <a href="mailto:davidchen@epclouds.com">littleDog</a> <br/>
 * @Description:
 * @Since: 2.0.0 <br/>
 * @Date: Created in 2019/11/6 15:22
 * @Modified By:
 */
public class FileController extends SelectorComposer<Component> implements EventListener {

    @Wire("div#explorer")
    private Div explorer;

    @Wire("button#prev")
    private Button prev;

    @Wire("button#save")
    private Button save;

    @Wire("menupopup#mp")
    private Menupopup mp;

    @Wire("label#basePath")
    private Label basePath;

    @Wire("center#container")
    private Component container;

    private FastDateFormat format = FastDateFormat.getInstance("yyyy-MM-dd HH:mm:ss");

    private File root;

    private Stack<File> stack = new Stack<>();

    @Override
    public void doAfterCompose(Component comp) throws Exception {
        super.doAfterCompose(comp);
        String path = WebApps.me().getTemplatePath() + "/" + Contexts.getEnv().getProjectId();
        dir(root = new File(FilenameUtils.normalize(path)));
        stack.add(root);
    }

    private void dir(File dir) {
        prev.setDisabled(dir.getPath().equals(root.getPath()));
        basePath.setValue(dir.getPath());
        explorer.getChildren().clear();
        save.setVisible(false);
        File[] files = dir.listFiles(new FilenameFilter() {
            @Override
            public boolean accept(File dir, String name) {
                return !name.startsWith(".");
            }
        });
        if (files != null) {
            Arrays.sort(files, (o1, o2) -> o1.isDirectory() ? 1 : -1);
            Div row = null;
            for (int i = 0; i < files.length; i++) {
                if (i % 3 == 0)
                    row = new Div();
                File f = files[i];
                row.setZclass("row");
                Div col = new Div();
                col.setZclass("col");
                if (f.isDirectory()) {
                    A folder = new A();
                    folder.setZclass("d-flex text-decoration-none pt-3");
                    folder.setIconSclass("z-icon-folder text-warning h1");
                    Vlayout layout = new Vlayout();
                    layout.setSclass("ml-2");
                    layout.appendChild(new Label(f.getName()));
                    Label md = new Label(Labels.getLabel("admin.log.md", new Object[]{format.format(f.lastModified())}));
                    md.setZclass("d-block text-truncate");
                    layout.appendChild(md);
                    layout.appendChild(new Label(Labels.getLabel("admin.log.size", new Object[]{f.length() / 1024})));
                    layout.setParent(folder);
                    folder.setAttribute("f", f);
                    folder.addEventListener(Events.ON_DOUBLE_CLICK, this);
                    folder.setContext(mp);
                    folder.setParent(col);
                } else {
                    A file = new A();
                    file.setZclass("d-flex text-decoration-none pt-3");
                    String ext = FilenameUtils.getExtension(f.getName()).toLowerCase();
                    if (ext.contains("css"))
                        file.setIconSclass("z-icon-css3 h1");
                    else if (ext.equals("js"))
                        file.setIconSclass("z-icon-jsfiddle h1");
                    else if (ext.equals("json"))
                        file.setIconSclass("z-icon-hashtag h1");
                    else if (ext.equals("jar"))
                        file.setIconSclass("z-icon-file-zip-o h1");
                    else if (ext.equals("jpg") || ext.equals("png") || ext.equals("jpeg") || ext.equals("gif"))
                        file.setIconSclass("z-icon-photo h1");
                    else
                        file.setIconSclass("z-icon-file-o h1");
                    Vlayout layout = new Vlayout();
                    layout.setSclass("ml-2");
                    layout.appendChild(new Label(f.getName()));
                    Label md = new Label(Labels.getLabel("admin.log.md", new Object[]{format.format(f.lastModified())}));
                    md.setZclass("d-block text-truncate");
                    layout.appendChild(md);
                    layout.appendChild(new Label(Labels.getLabel("admin.log.size", new Object[]{f.length() / 1024})));
                    layout.setParent(file);
                    file.setAttribute("f", f);
                    file.addEventListener(Events.ON_DOUBLE_CLICK, this);
                    file.setContext(mp);
                    file.setParent(col);
                }
                col.setParent(row);
                explorer.appendChild(row);
            }
        }
    }

    @Override
    public void onEvent(Event event) throws Exception {
        if (event.getTarget() instanceof Textbox) {
            Textbox input = (Textbox) event.getTarget();
            if (!Strings.isBlank(input.getValue())) {
                Files.createDirIfNoExists(new File(basePath.getValue() + File.separatorChar + input.getValue()));
                dir(stack.peek());
                event.getTarget().getRoot().detach();
            }
        } else if (event.getTarget() instanceof CMeditor) {
            save.setVisible(true);
        } else {
            File file = (File) event.getTarget().getAttribute("f");
            if (file.isDirectory()) {
                dir(file);
                stack.add(file);
            } else {
                container.getChildren().clear();
                save.setVisible(false);
                String ext = FilenameUtils.getExtension(file.getName()).toLowerCase();
                if (ext.equals("jpg") || ext.equals("png") || ext.equals("jpeg") || ext.equals("gif")) {
                    Image image = new Image();
                    image.setSrc("/template" + FilenameUtils.normalize(StringUtils.substringAfter(file.getPath(), root.getPath()), true));
                    BufferedImage img = ImageIO.read(file);
                    image.setHeight(img.getHeight() + "px");
                    image.setWidth(img.getWidth() + "px");
                    image.setZclass("border rounded mx-auto d-block");
                    image.setParent(container);
                } else if (ext.contains("css") || ext.equals("js") || ext.equals("json") || ext.equals("zul")) {
                    CMeditor editor = new CMeditor();
                    editor.setHflex("1");
                    editor.setVflex("1");
                    editor.setFoldGutter(true);
                    editor.setAutoCloseTags(true);
                    editor.setLineNumbers(true);
                    editor.setCollapse(true);
                    editor.setBorder("none");
                    //editor.setReadonly(true);
                    editor.setValue(FileUtils.readFileToString(file));
                    editor.addEventListener(Events.ON_CHANGE, this);
                    save.setAttribute("f", file);
                    if (ext.equals("js"))
                        editor.setMode("javascript");
                    else if (ext.equals("zul"))
                        editor.setMode("eppage");
                    else editor.setMode(ext);
                    editor.setParent(container);
                }
            }
        }
    }

    @Listen("onOpen = #mp")
    public void onContext(OpenEvent oe) {
        if (oe.isOpen()) {
            oe.getTarget().setAttribute("f", oe.getReference().getAttribute("f"));
            File f = (File) oe.getTarget().getAttribute("f");
            oe.getTarget().getChildren().get(0).setVisible(f.isDirectory());
            oe.getTarget().getChildren().get(1).setVisible(!f.isDirectory());
        }
    }

    @Listen("onUpload = #upload")
    public void onUpload(UploadEvent evt) {
        try {
            File file = new File(FilenameUtils.normalize(basePath.getValue() + "/" + evt.getMedia().getName()));
            FileUtils.writeByteArrayToFile(file, evt.getMedia().getByteData());
            dir(file.getParentFile());
        } catch (IOException e) {
            MessageBox.showMessage(Labels.getLabel("message.dialog.title.error"), e.getMessage());
        }
    }

    @Listen("onClick = menuitem")
    public void onMenuitem(Event evt) {
        File f = (File) evt.getTarget().getParent().getAttribute("f");
        int idx = evt.getTarget().getParent().getChildren().indexOf(evt.getTarget());
        if (f.isDirectory()) {
            if (idx == 0) {//打开
                dir(f);
                stack.add(f);
            } else {//删除
                delete(f);
            }
        } else {
            if (idx == 1) {//下载
                try {
                    Filedownload.save(f, Files.getContentType(FilenameUtils.getExtension(f.getName())));
                } catch (FileNotFoundException e) {
                }
            } else {//删除
                delete(f);
            }
        }
    }

    private void delete(File file) {
        Messagebox.show(Labels.getLabel("admin.service.op.confirm",
                new Object[]{Labels.getLabel("button.delete") + "'" + file.getName() + "'"}), Labels
                        .getLabel("admin.service.op.title"), Messagebox.CANCEL
                        | Messagebox.OK, Messagebox.QUESTION,
                new EventListener<Event>() {
                    @Override
                    public void onEvent(Event evt) throws Exception {
                        if (evt.getName().equals(Messagebox.ON_OK)) {
                            FileUtils.deleteQuietly(file);
                            dir(stack.peek());
                        }
                    }
                });
    }

    @Listen("onClick = #prev")
    public void onPrev() {
        stack.pop();
        dir(stack.peek());
    }

    @Listen("onClick = #save")
    public void onSave() {
        File file = (File) save.getAttribute("f");
        CMeditor editor = (CMeditor) save.getRoot().query("cmeditor");
        Files.write(file, editor.getValue());
        save.setVisible(false);
    }

    @Listen("onClick = #create")
    public void oCreate() {
        Window dialog = new Window(Labels.getLabel("explorer.folder"), "normal", true);
        Hlayout hlayout = new Hlayout();
        hlayout.appendChild(new Label(Labels.getLabel("admin.project.name") + ":"));
        Textbox input = new Textbox();
        input.addEventListener(Events.ON_OK, this);
        input.addForward(Events.ON_CANCEL, dialog, Events.ON_CLOSE);
        hlayout.appendChild(input);
        hlayout.setParent(dialog);
        dialog.setPage(prev.getPage());
        dialog.doHighlighted();
    }

}
